// C library headers
#include <assert.h>
#include <atomic>
#include <cstdint>
#include <iostream>
#include <signal.h>
#include <stdio.h>
#include <string.h>
#include <vector>

#include "check_sum.h"

#include <CppLinuxSerial/SerialPort.hpp>
using namespace mn::CppLinuxSerial;


static std::atomic_bool run_flag{true};


static int32_t rx_tool(SerialPort* port, void *buff, int32_t len) {
  uint8_t *rx_buff = static_cast<uint8_t *>(buff);
  int32_t rx_acc = 0;
  while (rx_acc < len && run_flag.load()) {
    auto rx_num = port->Read(rx_buff + rx_acc, len - rx_acc);
    rx_acc += (rx_num != 0) ? rx_num : 0;
  }

  return rx_acc;
}


int main() {
  uint32_t max_pl_len = 0;
  int32_t frame_count = 0;

  SerialPort serialPort("/dev/ttyS1", BaudRate::B_115200, NumDataBits::EIGHT, Parity::NONE, NumStopBits::ONE);
  serialPort.SetTimeout(0);
  serialPort.Open();

  while (run_flag.load()) {
    uint32_t pl_len = 0;
    auto rx_len = rx_tool(&serialPort, &pl_len, sizeof(pl_len));
    if (!run_flag.load())
      break;

    assert(pl_len > 0 && pl_len < (8 * 1024));
    std::vector<uint8_t> rx_payload(pl_len);
    uint8_t *rx_data = rx_payload.data();
    rx_tool(&serialPort, rx_data, pl_len);

    uint32_t rd_cs = *((uint32_t *)(rx_data + pl_len - 4));
    uint32_t calc_cs = make_checksum_32(rx_data, pl_len - 4);
    if (calc_cs != rd_cs) {
      std::cout << std::hex << "checksum not match: " << rd_cs << " vs " << calc_cs << std::dec << std::endl;
      break;
    }

    frame_count++;
    std::cout << "received a frame, frame count: " << frame_count << std::endl;
    if (pl_len > max_pl_len) {
      max_pl_len = pl_len;
    }
  }

  std::cout << "frame count: " << frame_count << std::endl;
  return 0;
}
